<template>
  <el-dialog :title="$t('api_test.request.parameters_advance')"
             :visible.sync="itemValueVisible"
             class="advanced-item-value"
             width="70%">
    <el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
      <el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">
        <el-row type="flex" :gutter="20">
          <el-col :span="6" class="col-height">
            <div>
              <el-input size="small" v-model="filterText"
                        :placeholder="$t('api_test.request.parameters_mock_filter_tips')"/>
              <el-tree class="filter-tree" ref="tree" :data="mockFuncs" :props="treeProps"
                       default-expand-all @node-click="selectVariable"
                       :filter-node-method="filterNode"></el-tree>
            </div>
          </el-col>
          <el-col :span="6" v-for="(itemFunc, itemIndex) in mockVariableFuncs" :key="itemIndex">
            <div v-for="(func, funcIndex) in funcs"
                 :key="`${itemIndex}-${funcIndex}`">
              <el-row>
                <el-col :span="12">
                  <el-radio size="mini" v-model="itemFunc.name" :label="func.name"
                            @change="methodChange(itemFunc, func)"/>
                </el-col>
                <el-col :span="12" v-if="itemFunc.name === func.name">
                  <div v-for="(p, pIndex) in itemFunc.params" :key="`${itemIndex}-${funcIndex}-${pIndex}`">
                    <el-input :placeholder="p.name" size="mini" v-model="p.value" @change="showPreview"/>
                  </div>
                </el-col>
              </el-row>
            </div>
          </el-col>
        </el-row>
      </el-tab-pane>
      <el-tab-pane :label="$t('api_test.variable')">
        <el-row>
          <el-col :span="6" class="col-height">
            <div v-if="environment">
              <p>{{ $t('api_test.environment.environment') }}</p>
              <el-tree :data="environmentParams" :props="treeProps" @node-click="selectVariable"></el-tree>
            </div>
            <div v-if="scenario">
              <p>{{ $t('api_test.scenario.scenario') }}</p>
              <el-tree :data="scenarioParams" :props="treeProps" @node-click="selectVariable"></el-tree>
            </div>
            <div v-if="preRequestParams">
              <p>{{ $t('api_test.request.parameters_pre_request') }}</p>
              <el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
            </div>
          </el-col>
          <el-col :span="18" class="col-height">
            <div>
              <h1>{{ $t('api_test.request.jmeter_func') }}</h1>
              <el-table border :data="jmeterFuncs" class="adjust-table table-content" height="400">
                <el-table-column prop="type" label="Type" width="150"/>
                <el-table-column prop="name" label="Functions" width="250"/>
                <el-table-column prop="description" label="Description"/>
              </el-table>
            </div>
          </el-col>
        </el-row>
      </el-tab-pane>
    </el-tabs>
    <el-form>
      <el-form-item>
        <el-input :placeholder="valueText" size="small"
                  v-model="itemValue"/>
      </el-form-item>
    </el-form>
    <div style="padding-top: 10px;">
      <el-row type="flex" align="middle">
        <el-col :span="12">
          <el-button size="small" type="primary" plain @click="saveAdvanced()">
            {{ $t('commons.save') }}
          </el-button>
          <el-button size="small" type="info" plain @click="addFunc()" v-if="currentTab === 0">
            {{ $t('api_test.request.parameters_advance_add_func') }}
          </el-button>
          <el-button size="small" type="success" plain @click="showPreview()" v-if="currentTab === 0">
            {{ $t('api_test.request.parameters_preview') }}
          </el-button>
        </el-col>
        <el-col>
          <div> {{ itemValuePreview }}</div>
        </el-col>
      </el-row>
    </div>
  </el-dialog>
</template>

<script>
import {calculate, Scenario} from "@/business/components/api/test/model/ScenarioModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";

export default {
  name: "MsApiVariableAdvance",
  props: {
    parameters: Array,
    environment: Object,
    scenario: Scenario,
    currentItem: Object,
  },
  data() {
    return {
      itemValueVisible: false,
      filterText: '',
      environmentParams: [],
      scenarioParams: [],
      preRequests: [],
      preRequestParams: [],
      treeProps: {children: 'children', label: 'name'},
      currentTab: 0,
      itemValue: null,
      itemValuePreview: null,
      funcs: [
        {name: "md5"},
        {name: "base64"},
        {name: "unbase64"},
        {
          name: "substr",
          params: [{name: "start"}, {name: "length"}]
        },
        {
          name: "concat",
          params: [{name: "suffix"}]
        },
        {name: "lconcat", params: [{name: "prefix"}]},
        {name: "sha1"},
        {name: "sha224"},
        {name: "sha256"},
        {name: "sha384"},
        {name: "sha512"},
        {name: "lower"},
        {name: "upper"},
        {name: "length"},
        {name: "number"}
      ],
      mockFuncs: MOCKJS_FUNC.map(f => {
        return {name: f.name, value: f.name}
      }),
      jmeterFuncs: JMETER_FUNC,
      mockVariableFuncs: [],
      jmeterVariableFuncs: [],
    }
  },
  computed: {
    valueText() {
      return this.valuePlaceholder || this.$t("api_test.value");
    }
  },
  mounted() {
    this.prepareData();
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val);
    },
  },
  methods: {
    open() {
      this.itemValueVisible = true;
    },
    prepareData() {
      if (this.scenario) {
        let variables = this.scenario.variables;
        this.scenarioParams = [
          {
            name: this.scenario.name,
            children: variables.filter(v => v.name).map(v => {
              return {name: v.name, value: '${' + v.name + '}'}
            }),
          }
        ];
        if (this.environment) {
          let variables = JSON.parse(this.environment.variables);
          this.environmentParams = [
            {
              name: this.environment.name,
              children: variables.filter(v => v.name).map(v => {
                return {name: v.name, value: '${' + v.name + '}'}
              }),
            }
          ];
        }
        let i = this.scenario.requests.indexOf(this.request);
        this.preRequests = this.scenario.requests.slice(0, i);
        this.preRequests.forEach(r => {
          let js = r.extract.json.map(v => {
            return {name: v.variable, value: v.value}
          });
          let xs = r.extract.xpath.map(v => {
            return {name: v.variable, value: v.value}
          });
          let rx = r.extract.regex.map(v => {
            return {name: v.variable, value: v.value}
          });
          let vs = [...js, ...xs, ...rx];
          if (vs.length > 0) {
            this.preRequestParams.push({name: r.name, children: vs});
          }
        });
      }
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    selectVariable(node) {
      this.itemValue = node.value;
    },
    selectTab(tab) {
      this.currentTab = +tab.index;
      this.itemValue = null;
      this.itemValuePreview = null;
    },
    showPreview() {
      // 找到变量本身
      if (!this.itemValue) {
        return;
      }
      let index = this.itemValue.indexOf("|");
      if (index > -1) {
        this.itemValue = this.itemValue.substring(0, index).trim();
      }

      this.mockVariableFuncs.forEach(f => {
        if (!f.name) {
          return;
        }
        this.itemValue += "|" + f.name;
        if (f.params) {
          this.itemValue += ":" + f.params.map(p => p.value).join(",");
        }
      });

      this.itemValuePreview = calculate(this.itemValue);
    },
    methodChange(itemFunc, func) {
      let index = this.mockVariableFuncs.indexOf(itemFunc);
      this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
      // 这里要用 deep copy
      this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
      this.showPreview();
    },
    addFunc() {
      if (this.mockVariableFuncs.length > 4) {
        this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
        return;
      }
      if (this.mockVariableFuncs.length > 0) {
        let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
        if (!func.name) {
          this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
          return;
        }
        if (func.params) {
          for (let j = 0; j < func.params.length; j++) {
            if (!func.params[j].value) {
              this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
              return;
            }
          }
        }
      }
      this.mockVariableFuncs.push({name: '', params: []});
    },
    saveAdvanced() {
      this.currentItem.value = this.itemValue;
      this.itemValueVisible = false;
      this.mockVariableFuncs = [];
    }
  }
}
</script>

<style scoped>
.col-height {
  height: 40vh;
  overflow: auto;
}
</style>
